import pymongo
from datetime import datetime
import pandas as pd
from typing import Dict, List, Tuple
from random import randint

# 连接到MongoDB
client = pymongo.MongoClient('mongodb://localhost:27017/')
db = client['test']
logs_collection = db['logs']
books_collection = db['book']
rankings_collection = db['rankings']


def generate_trend() -> int:
    """
    生成趋势数据，范围从 -5到5
    """
    return randint(-5, 5)


def get_book_details(book_id: str) -> Dict:
    """根据图书ID获取完整图书信息"""
    book = books_collection.find_one({"_id": book_id})
    if not book:
        return None

    return {
        "id": str(book["_id"]),
        "f_id": book.get("f_id", 0),
        "s_id": book.get("s_id", 0),
        "t_id": book.get("t_id", 0),
        "title": book.get("title", "未知"),
        "author": book.get("author", "未知"),
        "cover": book.get("cover", ""),
        "publish_date": book.get("publish_date", datetime.now()),
        "rating": book.get("rating", 3.0)
    }


def generate_book_rankings() -> Dict[str, List[Dict]]:
    """生成完整的图书排行榜数据"""
    # 1. 获取基础数据
    logs = list(logs_collection.find({}))
    books = list(books_collection.find({}))

    if not logs or not books:
        return {"error": "缺少日志或图书数据"}

    # 2. 创建图书指标计算字典
    book_metrics = {}
    for book in books:
        book_id = str(book['_id'])
        book_metrics[book_id] = {
            **get_book_details(book['_id']),  # 获取完整图书信息
            'read_count': 0,
            'collect_count': 0,
            'review_count': 0,
            'like_count': 0,
            'share_count': 0,
            'total_score': 0.0,
            'recent_popularity': 0,  # 近期热度
        }

    # 3. 计算指标（基于最近30天的数据）
    cutoff_date = datetime.now() - pd.Timedelta(days=30)

    for log in logs:
        book_id = str(log['b_id'])
        if book_id not in book_metrics:
            continue

        action = log['action']
        timestamp = log['timestamp']

        # 基础计数
        if action == 'read':
            book_metrics[book_id]['read_count'] += 1
        elif action == 'collect':
            book_metrics[book_id]['collect_count'] += 1
        elif action == 'review':
            book_metrics[book_id]['review_count'] += 1
        elif action == 'like':
            book_metrics[book_id]['like_count'] += 1
        elif action == 'share':
            book_metrics[book_id]['share_count'] += 1

        # 计算近期热度（最近7天权重更高）
        if timestamp > cutoff_date:
            time_weight = 2.0 if timestamp > (datetime.now() - pd.Timedelta(days=7)) else 1.5
            book_metrics[book_id]['recent_popularity'] += time_weight

    # 4. 计算综合评分
    for metrics in book_metrics.values():
        # 基础分 = 基础评分 + 评论数*0.2 + 收藏数*0.1
        base_score = metrics['rating'] + metrics['review_count'] * 0.2 + metrics['collect_count'] * 0.1

        # 热度分 = (阅读数 + 点赞数*0.5 + 分享数*0.8) / 100
        popularity_score = (metrics['read_count'] + metrics['like_count'] * 0.5 + metrics['share_count'] * 0.8) / 100

        # 近期热度分 = recent_popularity / 50
        recent_score = metrics['recent_popularity'] / 50

        # 综合评分 = 基础分*0.4 + 热度分*0.4 + 近期分*0.2
        metrics['total_score'] = round(
            base_score * 0.4 + popularity_score * 0.4 + recent_score * 0.2,
            2
        )

    # 5. 生成各类排行榜
    all_books = list(book_metrics.values())

    rankings = {
        # 热门榜（阅读量）
        'hot': sorted(
            all_books,
            key=lambda x: x['read_count'],
            reverse=True
        )[:100],

        # 新书榜（出版日期+近期热度）
        'new': sorted(
            all_books,
            key=lambda x: (
                x['publish_date'],
                x['recent_popularity']
            ),
            reverse=True
        )[:100],

        # 口碑榜（评分+评论数）
        'reputation': sorted(
            all_books,
            key=lambda x: (
                x['rating'],
                x['review_count']
            ),
            reverse=True
        )[:100],

        # 综合榜（综合评分）
        'comprehensive': sorted(
            all_books,
            key=lambda x: x['total_score'],
            reverse=True
        )[:100],

        # 飙升榜（近期热度）
        'rising': sorted(
            all_books,
            key=lambda x: x['recent_popularity'],
            reverse=True
        )[:50],

        # 收藏榜
        'collect': sorted(
            all_books,
            key=lambda x: x['collect_count'],
            reverse=True
        )[:100],

        # 生成时间
        'generated_at': datetime.now()
    }

    return rankings


def save_rankings(rankings: Dict):
    """保存排行榜数据到MongoDB"""
    # 先清空旧数据
    rankings_collection.delete_many({})

    # 准备批量插入数据
    records = []
    for rank_type, books in rankings.items():
        if rank_type == 'generated_at':
            continue

        records.append({
            'rank_type': rank_type,
            'books': books[:10],  # 只保存前10名减少存储
            'generated_at': rankings['generated_at'],
            'top3': [
                {
                    'title': b['title'],
                    'score': b['total_score'],
                    'cover': b['cover'],
                    'author': b['author']
                }
                for b in books[:3]
            ]
        })

    # 批量插入
    if records:
        rankings_collection.insert_many(records)

    print(f"成功保存 {len(records)} 个排行榜到MongoDB")


def display_rankings(rankings: Dict):
    """展示排行榜数据"""
    print(f"\n=== 排行榜数据（生成时间：{rankings['generated_at']}）===")

    for rank_type in ['comprehensive', 'hot', 'new', 'rising', 'reputation']:
        books = rankings.get(rank_type, [])
        if not books:
            continue

        print(f"\n★ {rank_type.upper()}榜 TOP10 ★")
        for i, book in enumerate(books[:10], 1):
            print(f"{i}. {book['title']} - 作者:{book['author']} "
                  f"评分:{book['total_score']} (阅读:{book['read_count']} "
                  f"收藏:{book['collect_count']} 封面:{book['cover']})")


if __name__ == "__main__":
    # 生成排行榜
    rankings = generate_book_rankings()

    # 保存到数据库
    save_rankings(rankings)

    # 展示结果
    display_rankings(rankings)

    # 保存为Excel文件
    df = pd.DataFrame(rankings['comprehensive'])
    df.to_excel('book_rankings.xlsx', index=False)
    print("\n综合排行榜已保存为 book_rankings.xlsx")